package com.springboot.hiresystem.aop;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import java.util.Arrays;
import java.util.List;

@Aspect
@Component
@Slf4j
public class LoggingAspect {

    private static final int MAX_LOG_LENGTH = 1000; // 定义最大日志长度
    private static final String[] SENSITIVE_FIELD_NAMES = {"password", "creditCard"};

    @Before("execution(* com.springboot.hiresystem.controller..*.*(..))")
public void logBefore(JoinPoint joinPoint) {
    // 日志流水号
    MDC.put("logId", String.valueOf(System.currentTimeMillis()));
    // 请求参数
    ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    // 判断是否为空
    if (servletRequestAttributes == null) {
        return;
    }
    // 获取请求对象
    HttpServletRequest request = servletRequestAttributes.getRequest();
    // 获取请求地址
    String ip = request.getRemoteAddr();
    // 获取请求方法
    String method = request.getMethod();
    // 获取请求路径
    String uri = request.getRequestURI();
    // 获取请求类名
    String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();

    // 输出请求信息
    log.info("请求地址：{}", ip);
    log.info("请求方式：{}", method);
    log.info("请求路径：{}", uri);
    log.info("请求类名：{}", declaringTypeName);

    String remoteIPAddress = getRemoteIPAddress(request);
    log.info("客户端IP地址：{}", remoteIPAddress);

    // 获取所有参数
    Object[] args = joinPoint.getArgs();

    // 安全地处理参数日志输出
    StringBuilder paramsBuilder = new StringBuilder();
    for (Object arg : args) {
        if (arg instanceof ServletRequest || arg instanceof ServletResponse || arg instanceof MultipartFile) {
            paramsBuilder.append(arg.getClass().getSimpleName()).append(", ");
        } else {
            try {
                paramsBuilder.append(JSONObject.toJSONString(arg)).append(", ");
            } catch (Exception e) {
                paramsBuilder.append("<<").append(arg.getClass().getName()).append(">>").append(", ");
            }
        }
    }

    if (paramsBuilder.length() > 0) {
        paramsBuilder.setLength(paramsBuilder.length() - 2); // 去除最后一个逗号和空格
    }

    log.info("请求参数：{}", paramsBuilder.toString());

    // 排除敏感字段的版本
    PropertyPreFilters filters = new PropertyPreFilters();
    PropertyPreFilters.MySimplePropertyPreFilter excludeFilter = filters.addFilter();
    excludeFilter.addExcludes(SENSITIVE_FIELD_NAMES);

    List<Object> filteredArgs = Arrays.stream(args)
            .filter(arg -> !(arg instanceof ServletRequest || arg instanceof ServletResponse || arg instanceof MultipartFile))
            .toList();

    log.info("请求参数：(排除敏感字段) {}", JSONObject.toJSONString(filteredArgs, excludeFilter));
}

    // 环绕通知
    @Around("execution(* com.springboot.hiresystem.controller..*.*(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("-------------------LogAspect  doAround --------------------------");

        //开始时间
        long startTime = System.currentTimeMillis();
        Object result = null;

        try {
            // 执行目标方法
            result = joinPoint.proceed();

            // 排除敏感字段
            PropertyPreFilters filters = new PropertyPreFilters();
            PropertyPreFilters.MySimplePropertyPreFilter excludeFilter = filters.addFilter();
            excludeFilter.addExcludes(SENSITIVE_FIELD_NAMES);
            log.info("返回结果：{}", JSONObject.toJSONString(result, excludeFilter));

            // 结束时间
            long endTime = System.currentTimeMillis();
            // 计算方法执行时间
            long executionTime = endTime - startTime;
            // 输出日志
            log.info("方法执行时间：{} ms", executionTime);
        } catch (Exception e) {
            log.error("执行方法异常：{}", e.getMessage());
            log.error("执行方法异常：", e);
            throw e; // 重新抛出异常以保证调用链可见性
        } finally {
            // 输出日志流水号
            log.info("日志流水号：{}", MDC.get("logId"));
            // 清除日志流水号
            MDC.clear();
        }
        return result;

    }

    // 获取客户端IP地址
    public static String getRemoteIPAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

}
